package hershey.java07001.java_basic.a_demo.m001.non_access_modifiers;

/**
 * static修饰符：修饰变量、方法、代码块、嵌套类
 * static修饰符提供了类级别的成员，使得这些成员可以在不创建类实例的情况下访问，有助于实现一些全局性、共享性的功能。
 */
public class M001_Static {

    //static变量，也称为类变量，是属于类本身的，而不是某个实例。在类加载时初始化。每个类的实例共享同一个static变量。
    private static String static_variables_string = "static_variables_string";

    private String instance_variables_string = "instance_variables_string";

    private static int static_variables_int;

    // static代码块在类加载时执行，用于初始化static变量.在类加载时执行一次
    static {
        static_variables_int = 10;
        System.out.println("Static Code Block Executed, init static_variables_int = 10");
    }

    /**
     * static嵌套类（也称为静态内部类）是定义在另一个类中的静态类。与非静态内部类不同，静态嵌套类可以独立于其外部类实例存在。
     * 只能访问外部类的static成员。
     * static嵌套类在其外部类被加载时不会自动初始化，只有在首次被使用时才会初始化。比如创建其实例或访问其静态成员。
     */
    static class StaticInnerNestedClass {
        public void display() {
            System.out.println("I am a StaticInnerClass method <display()>");
        }
    }

    /**
     * 1. 静态变量
     *  存储:JVM的方法区(共享区- 类的元数据信息包括常量池、字段、方法数据)
     *  共享:类加载的时候初始化，内存中只有一份实例。且类的实例对象共享一份实例
     *  初始化：类首次被加载的时候，jvm会为变量分配内存和默认值。这发生在类的加载和链接（包括验证、准备、解析）阶段之后，初始化阶段之前。
     *  默认值：如果没有显式赋值，则被初始化为默认值，基本类型的默认值如下：整型（0）、浮点型（0.0）、布尔型（false）、引用类型（null）
     *
     * 2. 静态方法
     *  存储：方法区，属于类，不属于任何实例
     *  调用：通过类名调用，无需实例化
     *  初始化：类加载时，方法本身不初始化，只有在调用的时候才执行
     *
     * 3. 静态代码块
     *  存储：方法区
     *  执行顺序：一个类中存在多个代码块的时候，按照源码中出现的顺序执行
     *  执行：类加载的时候执行，且只执行一次。它们用于在类初始化时执行一些静态初始化操作，例如静态变量的复杂初始化。
     *
     * 4. 静态内部类
     *  存储: 内部类的元数据存储在方法区，其实例对象存储在堆中
     *  初始化：创建不依赖外部类。当实例化或者调用其静态资源的时候，才会初始化
     *  独立性：只能访问外部类的静态成员
     *  实例化：通过外部类名来实例化。例如：`OuterClass.StaticInnerClass inner = new OuterClass.StaticInnerClass();`
     *
     * 5. 底层实现
     *  当static成员第一次被调用的时候，类加载器就会加载该类。类加载器将字节码文件转换为内存中的类对象。
     *  在类加载的初始化阶段，JVM会执行`static`变量的初始化、`static`代码块。
     *
     * @param args
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {
        // 让main方法休眠5秒（1000毫秒）
        Thread.sleep(1000);
        System.err.println("开始执行test_static_variable...");
        test_static_variable();


        Thread.sleep(1000);
        System.err.println("开始执行test_static_method...");
        M001_Static.test_static_method();

        Thread.sleep(1000);
        System.err.println("开始执行(代码块)test_static_code_block...");
        test_static_code_block();

        Thread.sleep(1000);
        System.err.println("开始执行(嵌套类)test_static_nested...");
        test_static_nested();
    }

    private static void test_static_variable() {
        //可以通过类名直接访问。
        System.out.println("可以通过类名直接访问: "+M001_Static.static_variables_string);//static_string

        //所有实例共享一个static变量
        M001_Static m001_static = new M001_Static();
        m001_static.static_variables_string = "change_static_string";
        System.out.println("通过成员变量访问并且修改: "+ m001_static.static_variables_string);//change_static_string
        System.out.println("成员变量访问修改以后通过类访问: "+ M001_Static.static_variables_string);//change_static_string
    }

    private static void test_static_method() {
        // 不能直接访问实例变量和实例方法。实例变量是属于对象私有的。需要初始化一个对象，才可以访问到
        M001_Static m001_static = new M001_Static();
        System.out.println("不能直接访问实例变量，需要实例化一个对象才可以："+m001_static.instance_variables_string);//instance_variables_string

        // 可以在没有实例的情况下调用.不能访问实例变量和实例方法。可以访问其他static变量和方法。
        System.out.println("可以访问其他static变量和方法: "+ M001_Static.static_variables_string);//change_static_string
    }

    private static void test_static_code_block() {
        System.out.println("static代码块初始化的变量值"+M001_Static.static_variables_int);
    }

    private static void test_static_nested() {
        StaticInnerNestedClass staticInnerNestedClass = new StaticInnerNestedClass();
        staticInnerNestedClass.display();
    }
}
